/**
 * Class: DPoint3
 *
 * Purpose: 
 *
 * Created: Jan 23, 2010 @ 11:06:19 PM
 * @author Ken Scott
 */
package org.openfantasia.util.math;

import org.openfantasia.util.Copyable;

public class DPointN implements Copyable<DPointN> {

	private int N = 0;

	public double p[];


	public DPointN(int n) {
		this.N = n;
		p = new double[N];
	}


	public DPointN(double[] a) {
		if (a.length != N) {
			throw new IllegalArgumentException("Input array must be of length " + N + ", not " + a.length);
		}
		double[] result = new double[a.length];
		System.arraycopy(a, 0, result, 0, a.length);
		this.p = result;
	}


	public DPointN(DPointN pt) {
		this(pt.p);
	}


	public DPointN copy() {
		return new DPointN(p);
	}


	public void copy(DPointN that) {
		p = Math1D.copy(that.p);
	}


	public DPointN clear() {
		Math1D.fill(p, 0);
		return this;
	}


	public DPointN randomize(double mag) {
		for(int i = 0; i < N; i++) {
			p[i] = PMath.random(-1.0, 1.0);
		}
		return normalize().scale(mag);
	}


	public double dotp(DPointN other) {
		return Math1D.dotp(this.p, other.p);
	}


	public DPointN mulNoise(double frac) {
		for(int i = 0; i < N; i++) {
			p[i] *= PMath.random(-frac, frac);
		}
		return this;
	}


	public DPointN addNoise(double frac) {
		for(int i = 0; i < N; i++) {
			p[i] += PMath.random(-frac, frac);
		}
		return this;
	}


	public DPointN normalize() {
		double mag = Math1D.mag(p);
		for(int i = 0; i < N; i++) {
			p[i] /= mag;
		}
		return this;
	}


	public double mag() {
		return Math1D.mag(p);
	}


	public DPointN neg() {
		for(int i = 0; i < N; i++) {
			p[i] = -this.p[i];
		}
		return this;
	}


	public DPointN scale(double a) {
		for(int i = 0; i < N; i++) {
			p[i] *= a;
		}
		return this;
	}


	public DPointN abs() {
		for(int i = 0; i < N; i++) {
			p[i] = Math.abs(p[i]);
		}
		return this;
	}


	public DPointN add(double[] a) {
		if(a == null) {
			return this;
		}

		for(int i = 0; i < N; i++) {
			p[i] += a[i];
		}
		return this;
	}


	public DPointN add(DPointN a) {
		if(a == null) {
			return this;
		}

		return add(a.p);
	}


	public DPointN sub(double[] a) {
		if(a == null) {
			return this;
		}

		for(int i = 0; i < N; i++) {
			p[i] -= a[i];
		}
		return this;
	}


	public DPointN sub(DPointN a) {
		if(a == null) {
			return this;
		}

		return sub(a.p);
	}


	public DPointN mul(double[] a) {
		if(a == null) {
			return this;
		}

		for(int i = 0; i < N; i++) {
			p[i] *= a[i];
		}
		return this;
	}


	public DPointN mul(DPointN a) {
		if(a == null) {
			return this;
		}

		return mul(a.p);
	}


	public DPointN div(double[] a) {
		if(a == null) {
			return this;
		}

		for(int i = 0; i < N; i++) {
			p[i] /= a[i];
		}
		return this;
	}


	public DPointN div(DPointN a) {
		if(a == null) {
			return this;
		}

		return div(a.p);
	}


	public double[] toDouble() {
		double[] result = new double[N];
		System.arraycopy(this.p, 0, result, 0, N);
		return result;
	}


	public float[] toFloat() {
		float[] result = new float[N];
		for(int i = 0; i < N; i++) {
			result[i] = (float) p[i];
		}
		return result;
	}


	public int[] toInt() {
		int[] result = new int[N];
		for(int i = 0; i < N; i++) {
			result[i] = (int) p[i];
		}
		return result;
	}


	@Override
	public String toString() {
		return Math1D.toString(p);
	}
}